package WorldMap;


import java.util.ArrayList;
import java.io.*;

public class WorldMapIO {
	

	/*
	 * This function reads the amp from a text file			
	 */
	public ArrayList<StateNode> GetMap(String FileName)
	{

		ArrayList<StateNode> NewMap = new ArrayList<StateNode>();
		for (int i = 0; i < 50; i++)
		{
			NewMap.add(new StateNode());
		}
		
		//NS = Next Space Index
		int NS = 0;
		  
		      try{
		    // Open the file that is the first 
		    // command line parameter
		    FileInputStream fstream = new FileInputStream(FileName);
		    // Get the object of DataInputStream
		    DataInputStream in = new DataInputStream(fstream);
		        BufferedReader br = new BufferedReader(new InputStreamReader(in));
		    String strLine;
		    //Read File Line By Line
		    while ((strLine = br.readLine()) != null)   {

				StateNode NewSN = new StateNode();
				if (!(strLine == ""))
				{
					
		      // Print the content on the console
		    	//Get StateNumber
				NS = strLine.indexOf(" ");
		    	NewSN.StateNumber = Integer.parseInt(strLine.substring(0, NS));
		    	strLine = strLine.substring(NS + 1);
		    	//Get StateName
				NS = strLine.indexOf(" ");
		    	NewSN.StateName = strLine.substring(0, NS);
		    	strLine = strLine.substring(NS + 1);
		    		    	//Get State Edges
		    	do
		    	{
					NS = strLine.indexOf(" ");
				if (NS == -1)
				{
					NewSN.Edges.add(Integer.parseInt(strLine));
					strLine = "";
				}
				else
				{
					NewSN.Edges.add(Integer.parseInt(strLine.substring(0, NS)));
		    		strLine = strLine.substring(NS + 1);
				}
					
		    	}while(!(strLine == ""));
		    	
				NewMap.set(NewSN.StateNumber, NewSN);

				}
				else
				{
					System.out.println("No Data");
				}
		    }
		    //Close the input stream
		    in.close();
		    }catch (Exception e){//Catch exception if any
		      System.err.println("Error: " + e.getMessage());
		    }
		   
		   

		
		return NewMap;
	}
	
	/*
	 * this function sets the colors of each state 
	 */
	public ArrayList<StateNode> SetMapColor(ArrayList<StateNode> Map) throws Exception
	{
		ArrayList<Integer> AdjColor = new ArrayList<Integer>();
		
		
		System.out.println("Start of Set Color");
		Map = SetVisited(Map, false);	
			TQueue BFS_Queue = new TQueue(100);
			
			BFS_Queue.Enqueue(1);
			Map.get(1).Visited = true;


			int i = -1;
			int NewEdge = 0;
			do
			{
				i = BFS_Queue.Dequeue();
				if (Map.get(i).Color == -1)
				{
					AdjColor = new ArrayList<Integer>();
					for (int j = 0; j < Map.get(i).Edges.size(); j++)
					{
						NewEdge = Map.get(i).Edges.get(j);
						AdjColor.add(Map.get(NewEdge).Color );
						
					}
					Map.get(i).Color = ReturnNewColor(AdjColor);
				}
				for (int j = 0; j < Map.get(i).Edges.size(); j++)
				{
					NewEdge = Map.get(i).Edges.get(j);
					if (!Map.get(NewEdge).Visited)
					{
						BFS_Queue.Enqueue(NewEdge);
						Map.get(NewEdge).Visited = true;
						
					}
				}
				
			}while(!BFS_Queue.IsEmpty());
			
			System.out.println("End of Set Color");
			
			
		return Map;
	}
	

	/*
	 * This function is used by the SetMapColor function to assign a color to the state
	 */
	private int ReturnNewColor(ArrayList<Integer> AdjColor)
	{
		boolean Num0 = false;
		boolean Num1 = false;
		boolean Num2 = false;
		boolean Num3 = false;
		
		for (int i = 0; i < AdjColor.size(); i++)
		{
			if (AdjColor.get(i) == 0) 
			{
				Num0 = true;
			}
			if (AdjColor.get(i) == 1) 
			{
				Num1 = true;
			}
			if (AdjColor.get(i) == 2) 
			{
				Num2 = true;
			}
			if (AdjColor.get(i) == 3) 
			{
				Num3 = true;
			}
		}
		if (!Num0)
		{
			return 0;
		}
		if (!Num1)
		{
			return 1;
		}
		if (!Num2)
		{
			return 2;
		}
		if (!Num3)
		{
			return 3;
		}

		return 10;
	}


	/*
	 * this function calls the recursive DFS
	 */
	public void DFS(ArrayList<StateNode> Map, int StartingPoint, boolean PrintName, boolean PrintColor)
	{
		System.out.println("Start of DFS");
		Map = SetVisited(Map, false);	

		runDFS(Map, StartingPoint, true, true);
		System.out.println("End of DFS");
		
	}
	

	/*
	 * This is the recursive DFS
	 */
	public void runDFS(ArrayList<StateNode> Map, int StartingPoint, boolean PrintName, boolean PrintColor)
	{
		 Map.get(StartingPoint).Visited = true;
			if (PrintName)
			{
				System.out.print(Map.get(StartingPoint).StateName + " ");
				if (PrintColor)
				{
					System.out.print(GetColor(Map.get(StartingPoint).Color) + " ");
				}		
				System.out.println();
			}
		 for (int i = 0; i < Map.get(StartingPoint).Edges.size(); i++)
		 {
			if (Map.get(Map.get(StartingPoint).Edges.get(i)).Visited == false)
			{
			  runDFS(Map, Map.get(StartingPoint).Edges.get(i), PrintName, PrintColor);
			}
		 }
		
	}
	 

	/*
	 * This function runs the BFS
	 */
	public void BFS(ArrayList<StateNode> Map, int StartingPoint, boolean PrintName, boolean PrintColor) throws Exception
	{
		System.out.println("Start of BFS");
	Map = SetVisited(Map, false);	
		TQueue BFS_Queue = new TQueue(100);
		
		BFS_Queue.Enqueue(StartingPoint);
		Map.get(StartingPoint).Visited = true;
		
		int StateCount = 0;
		int i = -1;
		int NewEdge = 0;
		do
		{
			i = BFS_Queue.Dequeue();
			if (PrintName)
			{
				StateCount += 1;
				System.out.print(StateCount + " " + Map.get(i).StateName + " ");
				if (PrintColor)
				{
					System.out.print(GetColor(Map.get(i).Color) + " ");
				}		
				System.out.println();
			}
			for (int j = 0; j < Map.get(i).Edges.size(); j++)
			{
				NewEdge = Map.get(i).Edges.get(j);
				if (!Map.get(NewEdge).Visited)
				{
					BFS_Queue.Enqueue(NewEdge);
					Map.get(NewEdge).Visited = true;
					
				}
			}
			
		}while(!BFS_Queue.IsEmpty());
		
		System.out.println("End of BFS");
		
		
		
	}	
	

	/*
	 * This function sets the visited state of each State Node
	 */
	public ArrayList<StateNode> SetVisited(ArrayList<StateNode> Map, boolean NewVisitedVlaue)
	{
		for (int i = 0; i < Map.size(); i++)
		{
			Map.get(i).Visited = NewVisitedVlaue;
		}
		return Map;
	}
	

	/*
	 * This function translates the color number into a color name
	 */
	private String GetColor(int ColorNumber)
	{
		switch (ColorNumber)
		{
		case 0:
		{
			return "Yellow";
		}
		case 1:
		{
			return "Red";
		}
		case 2:
		{
			return "Green";
		}
		case 3:
		{
			return "Purple";
		}
		default:
		{
			return "No Color";
		}
		}
		 
	}
	
}
